#include "threadpool.h"
#include "pthread.h"
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"


//任务结构体
const int NUMBER=2;//依次添加两个线程

typedef struct Task
{
    void(*function)(void* arg);//函数指针
    void* arg;//普通指针
}Task;

//线程池结构体
struct ThreadPool
{
    //任务队列
    Task *taskQ;
    int queueCapacity;  //容量
    int queueSize;      //当前任务个数
    int queueFront;     //队头
    int queueRear;      //队尾

    pthread_t managerID;    //管理者线程ID
    pthread_t *threadIDs;   //工作的线程ID
    int minNum;             //最小线程数
    int maxNum;             //最大线程数
    int busyNum;            //忙的线程个数
    int liveNum;            //存活的线程个数
    int exitNum;            //要销毁的线程个数
    pthread_mutex_t mutexPool;//锁整个线程池
    pthread_mutex_t mutexBusy;//锁busyNum变量

    int shutdown;           //是否销毁线程池，销毁为1
    pthread_cond_t notFull; //任务队列是否满了
    pthread_cond_t notEmpty;//任务队列是否空了
};

ThreadPool *threadPoolCreate(int min,int max,int queueSize)
{
    ThreadPool *pool=(ThreadPool*)malloc(sizeof(ThreadPool));//创建堆内存
    
    do{
        if(pool==NULL)
        {
            printf("malloc threadpool fail...\n");
            break;
        }

        pool->threadIDs=(pthread_t*)malloc(sizeof(pthread_t)*max);

        if(pool->threadIDs==NULL)
        {
            printf("malloc threadpool fail...\n");
            break;
        }

        memset(pool->threadIDs,0,sizeof(pthread_t)*max);
        //线程id初始化为0

        pool->minNum=min;
        pool->maxNum=max;
        pool->busyNum=0;
        pool->liveNum=min;  //和最小个数相等
        pool->exitNum=0;

        if(phread_mutex_init(&pool->mutexPool,NULL)!=0 || 
            phread_mutex_init(&pool->mutexBusy,NULL)!=0 || 
            phread_cond_init(&pool->notEmpty,NULL)!=0 || 
            phread_cond_init(&pool->notFull,NULL)!=0)
        {
            printf("mutex or condition init fail...");
            break;
        }

        //任务队列
        pool->taskQ=malloc(sizeof(Task)*queueSize);
        pool->queueCapacity=queueSize;
        pool->queueSize=0;
        pool->queueFront=0;
        pool->queueRear=0;
        pool->shutdown=0;

        //创建线程
        pthread_create(&pool->managerID,NULL,manager,pool);

        for(int i=0;i<min,i++)
        {
            pthread_create(&pool->threadIDs[i],NULL,worker,pool);
        }

        return pool;

    }while(0);

    //释放资源
    if(pool->threadIDs)free(pool->threadIDs);
    if(pool->taskQ)free(pool->taskQ);
    if(pool)free(pool);

    return NULL;
}

//向线程池添加线程
void threadPoolAdd(ThreadPool* pool,void(*func)(void*),void* arg)
{
        pthread_mutex_lock(&pool->mutexPool);
        while(pool->queueSize==pool->queueCapacity && !pool->shutdown)
        {
            //阻塞生产者线程
            pthread_cond_wait(&pool.notFull,&pool->mutexPool);
        }
        if(pool->shutdown)
        {
            pthread_mutex_unlock(&pool->mutexPool);
            return;
        }
        //添加任务
        pool->taskQ[pool->queueRear].function=func;
        pool->taskQ[pool->queueRear].arg=arg;
        pool->queueRear=(pool->queueRear+1)%pool->queueCapacity;
        pool->queueSize++;

        pthread_cond_signal(&pool->notEmpty);//唤醒阻塞在条件变量的工作线程
        pthread_mutex_unlock(&pool->mutexPool);
}

int threadPoolDestroy(ThreadPool *pool)
{
    if(pool==NULL)
    {
        return -1;
    }

    //关闭线程池
    pool->shutdown=1;

    //阻塞回收管理者线程
    pthread_join(pool->managerID,NULL);

    //唤醒阻塞的消费者进程
    for(int i=0;i<pool->liveNum;i++)
    {
        pthread_cond_signal(&pool->notEmpty);
    }

    //释放堆内存
    if(pool->taskQ)
    {
        free(pool->taskQ);
    }

    if(pool->threadIDs)
    {
        free(pool->threadIDs);
    }
    pthread_mutex_destroy(&pool->mutexPool);
    pthread_mutex_destroy(&pool->mutexBusy);
    pthread_mutex_destroy(&pool->notEmpty);
    pthread_mutex_destroy(&pool->notFull);

    free(pool);
    pool=NULL; 
    return 0;

}

//获取线程池中工作的线程个数
int threadPoolBushNum(ThreadPool *pool)
{
    pthread_mutex_lock(&pool->mutexBusy);
    int busyNum = pool->busyNum;
    pthread_mutex_unlock(&pool->mutexBusy);

    return busyNum;
}

//获取线程池中活着的线程个数
int threadPoolAliveNum(ThreadPool *pool)
{
    pthread_mutex_lock(&pool->mutexPool);
    int aliveNum = pool->liveNum;
    pthread_mutex_unlock(&pool->mutexPool);

    return aliveNum;
}

//工作者线程
void *worker(void* arg)
{
    ThreadPool *pool=(ThreadPool*)arg;

    while(1)
    {
        pthread_mutex_lock(&pool->mutexPool);
        //当前队列是否为空
        while(pool->queueSize == 0 && !pool->shutdown)
        {
            //阻塞工作线程
            pthread_cond_wait(&pool->notEmpty,&pool->mutexPool);

            //判断是否要销毁线程
            if(pool->exitNum>0)
            {
                pool->exitNum--;
                if(pool->liveNum>pool->minNum)
                {
                    pool->liveNum--;
                    pthread_mutex_unlock(&pool->mutexPool);
                    threadExit(pool);
                }
 
            }
        }

        //判断线程池是否被关闭
        if(pool->shutdown)
        {
            //关闭了则打开互斥锁，退出当前的线程
            pthread_mutex_unlock(&pool->mutexPool);
            threadExit(pool);
        }

        //从任务队列中取任务
        Task task;
        task.function=pool->taskQ[pool->queueFront].function;
        task.arg=pool->taskQ[pool->queueFront].arg;
        //移动头结点
        pool->queueFront=(pool->queueFront+1)%pool->queueCapacity;
        pool->queueSize--;

        //解锁
        pthread_cond_signal(&pool->notFull);                                                    //唤醒生产者
        pthread_mutex_unlock(&pool->mutexPool);

        printf("thread %ld start working...\n",pthread_self());


        pthread_mutex_lock(&pool->mutexBusy);
        pool->busyNum++;
        pthread_mutex_unlock(&pool->mutexBusy);

        task.function(task.arg);
        free(task.arg);
        task.arg=NULL;

        printf("thread %ld end workong...\n",pthread_self());

        pthread_mutex_lock(&pool->mutexBusy);
        pool->busyNum--;
        pthread_mutex_unlock(&pool->mutexBusy);
    }
    return NULL;
}

//管理者每隔3s检查一次，先检查是否要添加线程，再检查是否要销毁线程
void *manager(void* arg)
{
    ThreadPool *pool=(ThreadPool*)arg;//类型转换
    while(!pool->shutdown)//shutdown等于0的时候开始干活
    {
        //每隔3秒检测一次
        sleep(3);

        //取出线程池中任务数量和当前线程数量
        pthread_mutex_lock(&pool->mutexPool);
        int queueSize=pool->queueSize;
        int liveNum=pool->liveNum;  //  取出存活线程的数量
        pthread_mutex_unlock(&pool->mutexPool);

        //取出忙的线程数量
        pthread_mutex_lock(&pool->mutexBusy);
        int busyNum=pool->busyNum;      //  取出工作线程数量
        pthread_mutex_unlock(&pool->mutexBusy);

        //什么时候添加线程（干活人少了）
        //任务的个数>存活的线程个数 && 存活的线程数<最大的线程数，否则不能继续添加新线程
        if(queueSize > liveNum && liveNum < pool->maxNum)
        {
            pthread_mutex_lock(&pool->mutexPool);
            int counter=0;
            for(int i=0; i<pool->maxNum && counter < NUMBER && pool->liveNum<pool->maxNum; i++)
            {
                if(pool->threadIDs[i]==0)//寻找没有存储线程id
                {
                    pthread_create(&pool->threadIDs[i],NULL,worker,pool);//把线程id放在数组里
                    counter++;
                    pool->liveNum++;
                }
            }
            pthread_mutex_unlock(&pool->mutexPool);
        }

        //销毁线程
        //忙的线程*2<存活的线程数 && 存活的线程数>最小线程数    存活的线程很多并且干活的线程很少
        if(busyNum*2 < liveNum && liveNum > pool->minNum)
        {
            pthread_mutex_lock(&pool->mutexPool); 
            pool->exitNum=NUMBER;  
            pthread_mutex_unlock(&pool->mutexPool);    

            //让工作线程自杀
            for(int i=0; i<NUMBER; i++)
            {
                pthread_cond_signal(&pool->notEmpty);
            }   
        }
    }
    return NULL;
}

//线程退出
void threadExit(ThreadPool* pool)
{
    pthread_t tid = pthread_self();
    for(int i=0;i<pool->maxNum;i++)
    {
        if(pool->threadIDs[i]==tid)
        {
            pool->threadIDs[i]=0;
            printf("threadExit() called,%ld exiting...\n",tid);
            break;
        }
    }
    pthread_exit(NULL);
}